//proto 文件解析器，主要用来解析proto文件

using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using Google.Protobuf;
using UnityEngine;

// proto文件总体结构
public class ProtoContent
{
    public string NameSpace;
    public List<MessageInfo> ReqMsg = new List<MessageInfo>();
    public List<MessageInfo> ResMsg = new List<MessageInfo>();
}

//proto文件中的message结构
public class MessageInfo
{
    public string Msg_name;
    public List<ClassInfo> infos = new List<ClassInfo>();
    public int Protocol_id;
    public string Desc = "";
}

//proto文件中的message中的字段
public class ClassInfo
{
    public string ClassType;
    public string ClassName;
    public bool Is_array;
    public string Desc = "";
}

public class ProtoParser 
{
    StringReader reader;

    //request flag
    readonly string ReqFlag = "Request";
    //response flag
    readonly string ResFlag = "Response";

    public ProtoContent Parse(string file)
    {
        ProtoContent content = new ProtoContent();
        reader = new StringReader(file);
        MessageInfo current_message = null;
        string line;
        while ((line = reader.ReadLine()) != null)
        {
            if(line.IndexOf("csharp_namespace") >= 0)
            {
                var package = RegexMgr.Instance.RegexBeginAndEnd(line,"csharp_namespace",";");
                content.NameSpace = package;
                content.NameSpace = content.NameSpace.Replace("=","");
                content.NameSpace = content.NameSpace.Replace("\"","");
                content.NameSpace = content.NameSpace.Trim();
                // content.NameSpace = content.NameSpace[0].ToString().ToUpper() + content.NameSpace.Substring(1);
            }
            else if(line.IndexOf("message") >= 0)
            {
                // var message = Regex.Match(line, string.Format(RegexStr,"message","{"));
                var message = RegexMgr.Instance.RegexBeginAndEnd(line,"message","{");
                var msgName = message.Trim();


                if(msgName.Contains(ReqFlag) || msgName.Contains(ResFlag))
                {
                    MessageInfo info = new MessageInfo();
                    info.Msg_name = msgName[0].ToString().ToUpper() + msgName.Substring(1);

                    var desc = RegexMgr.Instance.RegexBeginAndEnd(line,"//","").Trim();
                    info.Desc = desc;
                    current_message = info;
                }


            }else if(current_message != null)
            {
                
                if(line.IndexOf("}") >= 0 && line.Length == 1)
                {
                    if(current_message.Msg_name.Contains(ResFlag))
                    {
                        content.ResMsg.Add(current_message);
                    }else if(current_message.Msg_name.Contains(ReqFlag))
                    {
                        content.ReqMsg.Add(current_message);
                    }
                    current_message = null;
                }
                else if(line.IndexOf("=") >= 0)
                {
                    
                    if(line.IndexOf("Proto") < 0)
                    {
                        ClassInfo info = new ClassInfo();
                        info.Is_array = line.IndexOf("repeated") >= 0;

                        var spl = line.Split('=');
                        var str = spl[0].Trim();
                        var info_clip = str.Split(' ');
                        info.ClassType = ConvertProto(info_clip[info_clip.Length -2]);

                        var name = info_clip[info_clip.Length -1];
                        if(name.IndexOf("_") > 0)
                        {
                            var name_split = name.Split('_');
                            for (int i = 0; i < name_split.Length; i++)
                            {
                                var item = name_split[i];
                                name_split[i] = item[0].ToString().ToUpper() + item.Substring(1);
                            }
                            info.ClassName = string.Join("",name_split);
                        }else
                        {
                            info.ClassName = name[0].ToString().ToUpper() + name.Substring(1);
                        }
                        var desc = RegexMgr.Instance.RegexBeginAndEnd(line,"//","").Trim();
                        info.Desc = desc;
                        current_message.infos.Add(info);

                    }else if(line.IndexOf("Proto") > 0)
                    {

                        var begin = line.IndexOf("ID");
                        var end = line.LastIndexOf(";");
                        var proto_id = line.Substring(begin + 2, end - begin - 2);
                        proto_id = proto_id.Replace("=", "");
                        proto_id = proto_id.Trim();
                        current_message.Protocol_id = int.Parse(proto_id);
                    }
                }
            }
        }
        reader.Close();
        if(content.NameSpace == null)
        {
            //reset StringReader
            reader = new StringReader(file);
            
            while((line = reader.ReadLine()) != null)
            {
                if(line.IndexOf("package") >=0)
                {
                    var package = RegexMgr.Instance.RegexBeginAndEnd(line,"package",";");
                    var name = package;
                    name = name.Trim();
                    content.NameSpace = name;
                    break;
                }
            }
            reader.Close();
        }

        return content;
    }

    public string ParseNameSpace(string file)
    {
        var content = File.ReadAllText(file);
        reader = new StringReader(content);
        string name = "";
        string line;
        while((line = reader.ReadLine()) != null)
        {
            if(line.IndexOf("package") >=0)
            {
                var package = RegexMgr.Instance.RegexBeginAndEnd(line,"package",";");
                name = package;
                name = package;
                name = name.Replace("=","");
                name = name.Replace("\"","");
                name = name.Trim();
            }
            if(line.IndexOf("csharp_namespace") >= 0)
            {
                var package = RegexMgr.Instance.RegexBeginAndEnd(line,"csharp_namespace",";");
                name = package;
                name = name.Replace("=","");
                name = name.Replace("\"","");
                name = name.Trim();
                break;
            }
        }
        reader.Close();
        return name;
    }
    string ConvertProto(string type)
    {
        switch (type)
        {
            case "int32":
            case "sint32":
            case "sfixed32":
                return "int";
            case "int64":
            case "sint64":
            case "sfixed64":
                return "long";
            case "uint32":
            case "fixed32":
                return "uint";
            case "uint64":
            case "fixed64":
                return "ulong";
            case "bytes":
                    return "ByteString";
            default:
                return type;
        }
    }
}